// SmallObjAllocator.cpp: implementation of the SmallObjAllocator class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "SmallObjAllocator.h"
#include <assert.h>
#include "fstream.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

SmallObjAllocator::SmallObjAllocator(size_t chunkSize, size_t maxObjectSize)
{
	maxObjectSize_ = maxObjectSize;
	pool_.push_back(FixedAllocator());
	pLastAlloc_ = &pool_.back();
	pLastDealloc_ = pLastAlloc_;
#ifdef _DEBUG
	fstream file(_T("C:\\MemoryErrorReport.txt"), ios::out|ios::trunc);
	file<<_T("MemoryErrorReport\r\n");
	file.close();
#endif
}

SmallObjAllocator::~SmallObjAllocator()
{
	
}

void* SmallObjAllocator::Allocate(size_t numBytes)
{
	if(numBytes > maxObjectSize_)
	{
		return new unsigned char[numBytes];
	}

	if(numBytes == pLastAlloc_->blockSize_)
	{
		return pLastAlloc_->Allocate();
	}
	std::vector<FixedAllocator>::size_type pos = BinarySearch(numBytes);

	FixedAllocator* pFind = &pool_[pos];
	assert(pFind);

	if(pFind->blockSize_ == numBytes)
	{
		pLastAlloc_ = pFind;
		return pLastAlloc_->Allocate();
	}
	else
	{
		if(numBytes > pFind->blockSize_)
		{
			pFind++;
			pLastAlloc_ = pool_.insert(pFind, FixedAllocator());
		}
		else
		{
			pLastAlloc_ = pool_.insert(pFind, FixedAllocator());
		}
		assert(pLastAlloc_);
		pLastAlloc_->blockSize_ = numBytes;
		return pLastAlloc_->Allocate();
	}
}

void SmallObjAllocator::Deallocate(void* p, size_t size)
{
	if(size > maxObjectSize_)
	{
		delete []p;
		return;
	}

	if(pLastDealloc_->blockSize_ == size)
	{
		pLastDealloc_->Deallocate(p);
		return;
	}

	assert(p);
	std::vector<FixedAllocator>::size_type pos = BinarySearch(size);

	FixedAllocator* pFind = &pool_[pos];
	assert(pFind);
	
	assert(pFind->blockSize_ == size);
	pFind->Deallocate(p);
}

std::vector<FixedAllocator>::size_type SmallObjAllocator::BinarySearch(size_t size)
{
	assert(pool_.size() != 0);

	std::vector<FixedAllocator>::size_type _First = 0;
	std::vector<FixedAllocator>::size_type _Last = pool_.size() - 1;
	std::vector<FixedAllocator>::size_type _Cur = 0;
	std::vector<FixedAllocator>::size_type _Prev = -1;

	FixedAllocator* pFind = 0;
	while(true)
	{
		_Cur = (_First + _Last)/2;
		if(_Cur == _Prev)
		{
			return _Cur;
		}
		pFind = &pool_[_Cur];
		if(pFind->blockSize_ == size)
		{
			return _Cur;
		}
		else if(pFind->blockSize_ < size)
		{
			_First = _Cur;
		}
		else
		{
			_Last = _Cur;
		}
		_Prev = _Cur;
	}
}
